import React, { Component } from "react";
import "./App.css";
const isPlainObject = v =>
  Object.prototype.toString.call(v) === "[object Object]";
const isString = v => Object.prototype.toString.call(v) === "[object String]";
const isNumber = v => Object.prototype.toString.call(v) === "[object Number]";
const isBoolean = v => Object.prototype.toString.call(v) === "[object Boolean]";
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      change_target: "",
      result_target: "",
      headerParam: {
        $schema: "http://json-schema.org/draft-04/schema#",
        type: "object",
        description: "A notification to a user",
        additionalProperties: false,
        properties: {},
        required: []
      },
      collectionJson: "",
      collectionSampleValue: "",
      ramlValue: "",
      fileName: "temp",
      metadataFlag: true,
      metadata: { type: "object", $ref: "raml-util/schemas/metadata.schema" },
      fileListName: {}
    };
    this.raml = ".raml";
    this.collection = "Collection";
    this.json = ".json";
    this.sample = ".sample";
  }

  componentDidMount() {
    let fileName = "temp";
    let collectionSampleValue = this.collectionSample(fileName);
    let ramlValue = this.ramlInit(fileName);
    let collectionJson = this.collectionJSONCreate(fileName);
    let fileListName = this.createFileListName(fileName);
    this.setState({
      collectionSampleValue,
      ramlValue,
      collectionJson,
      fileListName
    });
  }
  createFileListName = fileName => {
    let temp = {};
    temp[`${this.state.fileName}${this.sample}`] = `change_target`;
    temp[
      `${this.state.fileName}${this.collection}${this.sample}`
    ] = `collectionSampleValue`;
    temp[
      `${this.state.fileName}${this.collection}${this.json}`
    ] = `collectionJson`;
    temp[`${this.state.fileName}${this.json}`] = `result_target`;
    temp[`${this.state.fileName}${this.raml}`] = `ramlValue`;
    return temp;
  };
  createJSON = () => {
    let result_target = this.change();
    this.setState({
      result_target
    });
  };
  change = () => {
    let target = this.state.change_target;
    if (!!target) {
      let param = this.state.headerParam;
      let value = JSON.parse(target);
      let key = Object.keys(value);
      let properties = {};
      key.forEach(k => {
        let type = this.objType(value[k]);
        let temp = {};
        temp.type = type;
        temp.description = k;
        properties[k] = temp;
      });

      if (this.state.metadataFlag) properties.metadata = this.state.metadata;

      param.properties = properties;
      let result_target = this.formatJSONIndnt(param);
      return result_target;
    }
    return "";
  };
  collectionJSONCreate = fileName => {
    let param = this.state.headerParam;
    let temp = {};
    temp[`${fileName}Group`] = {
      description: `List of ${fileName}Group`,
      type: "array",
      items: {
        type: "object",
        $ref: `${fileName}.json`
      }
    };
    temp["totalRecords"] = { type: "integer" };
    param.properties = temp;
    let required = [`${fileName}Group`, "totalRecords"];
    param.required = required;

    return this.formatJSONIndnt(param);
  };
  download = (filename, text) => {
    let element = document.createElement("a");
    element.setAttribute(
      "href",
      "data:text/plain;charset=utf-8," + encodeURIComponent(text)
    );
    element.setAttribute("download", filename);

    element.style.display = "none";
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
  };
  objType = sample => {
    let temp = sample;
    if (!!temp) {
      if (isNumber(temp)) return "number";
      if (isString(temp)) return "string";
      if (isPlainObject(temp)) return "object";
      if (isBoolean(temp)) return "boolean";
    } else {
      return "string";
    }
    return "string";
  };
  ramlInit = () => {
    let value = `#%RAML 1.0

    title: Party API
    baseUri: #
    version: v1
    
    documentation:
      - title: mod-party API
        content: This documents the API calls that can be made to post party for users, and to get them
    
    types:
      ${this.state.fileName}: !include ${this.state.fileName}.json
      ${this.state.fileName}Collection: !include ${this.state.fileName}Collection.json
      errors: !include raml-util/schemas/errors.schema
    
    traits:
      validate: !include raml-util/traits/validation.raml
      language: !include raml-util/traits/language.raml
      pageable:  !include raml-util/traits/pageable.raml
      searchable: !include raml-util/traits/searchable.raml
    
    resourceTypes:
      collection: !include raml-util/rtypes/collection.raml
      collection-item: !include raml-util/rtypes/item-collection.raml
    
    /${this.state.fileName}:
      displayName: ${this.state.fileName}
      description: ${this.state.fileName} from the system to some user
      type:
        collection:
          schemaCollection: ${this.state.fileName}Collection
          schemaItem: ${this.state.fileName}
          exampleCollection: !include examples/${this.state.fileName}Collection.sample
          exampleItem: !include examples/${this.state.fileName}.sample
    
      post:
        is: [validate]
      put:
        is: [validate]
      get:
        is: [
          searchable: {description: "with valid searchable fields: for example link = 1234", example: "link=/users/1234"},
          pageable,
          validate
        ]
      delete:
        is: [validate]
      /{id}:
          displayName: ${this.state.fileName}
          description: Get, Delete or Update a specific ${this.state.fileName}
          type:
            collection-item:
              schema: ${this.state.fileName}
              exampleItem: !include examples/${this.state.fileName}.sample
    `;
    return value;
  };
  formatJsonStrAsObj = sample => {
    let temp = sample;

    if (isString(temp)) {
      // 因为有解析失败的可能，使用 try catch 做相应处理
      try {
        temp = JSON.parse(temp);
      } catch (ex) {
        // parse error，return this sample
        return sample;
      }
    }

    if (isPlainObject(temp)) {
      temp = { ...temp };

      Object.keys(temp).forEach(key => {
        const item = temp[key];

        // 字符串或者对象进行递归确认
        if (isString(item) || isPlainObject(item)) {
          temp[key] = this.formatJsonStrAsObj(item);
        }
      });
    }

    return temp;
  };
  formatJSONIndnt = (sample, indnt = 2) => {
    const newSample = this.formatJsonStrAsObj(sample);

    if (isString(newSample)) return newSample;

    try {
      return JSON.stringify(newSample, null, indnt);
    } catch (ex) {
      return newSample.toString();
    }
  };
  collectionSample = name => {
    let temp = {};
    temp[`${name}Group`] = [];
    temp[`totalRecords`] = 0;
    return this.formatJSONIndnt(temp);
  };
  componentDidUpdate() {}

  render() {
    return (
      <div>
        <h1>根据JSON格式生成Raml配套文件</h1>
        <hr />
        <div className="div-param">
          <div>
            <label>$schema:</label>
            <input
              defaultValue={this.state.headerParam.$schema}
              onBlur={e => {
                let $schema = e.target.value;
                this.setState(par => {
                  par.headerParam.$schema = $schema;
                });
              }}
            ></input>
          </div>
          <div>
            <label>type:</label>
            <input
              defaultValue={this.state.headerParam.type}
              onBlur={e => {
                let type = e.target.value;
                this.setState(par => {
                  par.headerParam.type = type;
                });
              }}
            ></input>
          </div>
          <div>
            <label>description:</label>
            <input
              defaultValue={this.state.headerParam.description}
              onBlur={e => {
                let description = e.target.value;
                this.setState(par => {
                  par.headerParam.description = description;
                });
              }}
            ></input>
          </div>
          <div>
            <label>is metadata </label>
            <input
              type="checkBox"
              defaultChecked={this.state.metadataFlag}
              onClick={e => {
                let checked = e.target.checked;
                this.setState(par => {
                  par.metadataFlag = checked;
                });
              }}
            ></input>
          </div>
          <div>
            <label>additionalProperties:</label>
            <input
              defaultValue={this.state.headerParam.additionalProperties}
              onBlur={e => {
                let additionalProperties = e.target.value;
                this.setState(par => {
                  par.headerParam.additionalProperties = additionalProperties;
                });
              }}
            ></input>
          </div>
          <div>
            <label>file name:</label>
            <input
              defaultValue={this.state.fileName}
              onBlur={e => {
                let fileName = e.target.value;
                let collectionSampleValue = this.collectionSample(fileName);
                let ramlValue = this.ramlInit(fileName);
                let collectionJson = this.collectionJSONCreate(fileName);
                let fileListName = this.createFileListName(fileName);
                let result_target = this.change();

                this.setState({
                  result_target,
                  fileListName,
                  fileName,
                  collectionSampleValue,
                  ramlValue,
                  collectionJson
                });
              }}
            ></input>
            <button
              onClick={() => {
                this.createJSON();
              }}
            >
              生成
            </button>
            <button
              onClick={() => {
                let temp = this.state.fileListName;
                let list = Object.keys(temp);
                list.forEach(item => {
                  this.download(item, this.state[temp[item]]);
                });
              }}
            >
              {" "}
              下载
            </button>
          </div>
        </div>
        <div className="div-head">
          <div className="div-txtinput">
            <div>
              <span>{`${this.state.fileName}${this.sample}`}</span>
            </div>
            <textarea
              className="div-txtarea"
              id="change_target"
              defaultValue={this.state.change_target}
              onBlur={e => {
                let target = e.target.value;
                let change_target = this.formatJSONIndnt(target);
                e.target.value = change_target;
                this.setState({
                  change_target
                });
              }}
            ></textarea>
          </div>
          <div className="div-txtinput">
            <div>
              <span>{`${this.state.fileName}${this.json}`}</span>
            </div>
            <textarea
              className="div-txtarea"
              id="result_target"
              defaultValue={this.state.result_target}
              onBlur={e => {
                let result_target = e.target.value;
                this.setState({
                  result_target
                });
              }}
            ></textarea>
          </div>
          <div className="div-txtinput">
            <div>
              <span>{`${this.state.fileName}${this.collection}${this.sample}`}</span>
            </div>
            <textarea
              className="div-txtarea"
              id="result_target"
              defaultValue={this.state.collectionSampleValue}
              onBlur={e => {
                let collectionSampleValue = e.target.value;
                this.setState({
                  collectionSampleValue
                });
              }}
            ></textarea>
          </div>
          <div className="div-txtinput">
            <div>
              <span>{`${this.state.fileName}${this.collection}${this.json}`}</span>
            </div>
            <textarea
              className="div-txtarea"
              id="result_target"
              defaultValue={this.state.collectionJson}
              onBlur={e => {
                let collectionJson = e.target.value;
                this.setState({
                  collectionJson
                });
              }}
            ></textarea>
          </div>
          <div className="div-txtinput">
            <div>
              <span>{`${this.state.fileName}${this.raml}`}</span>
            </div>
            <textarea
              className="div-txtarea"
              id="result_target"
              defaultValue={this.state.ramlValue}
              onBlur={e => {
                let ramlValue = e.target.value;
                this.setState({
                  ramlValue
                });
              }}
            ></textarea>
          </div>
        </div>
      </div>
    );
  }
}

App.propTypes = {};

export default App;
